#include "PvpPart.h"
#include "Character/Player.h"
#include "Character/MovePart.h"
#include "Character/drop/DropMgr.h"
#include "Character/monster/MonsterRefCfg.h"
#include "Scene/MapMgr.h"

#include "Common/TableData/PkmodePkWantedCfg.h"
#include "Common/TableDataEx/PkModeCfg.h"
#include "Common/TableData/ConstantConstantCfg.h"
#include "ProtoBuffer/AllProtocol.h"
#include "Common/ReliveMgr/ReliveMgr.h"

const uint8_t g_const_PK_Level = 5;  //pk最大等级(C级 B级 A级 S级 SSS级)

#define PK_VALUE_REFRESH_TIME 3600000

PvpPart::PvpPart()
{
	m_pkMode = 0;//PK_MODE_CAMP;
	m_pkKillingValue = 0;
	m_lastSubPkValueTime = 0;
	m_onlineTime = 0;
	m_pkValueTimerFlag = false;
}

PvpPart::~PvpPart()
{

}

void PvpPart::CountKillValueTimer()
{
	if (m_pkValueTimerFlag == false && m_pkKillingValue > 0)
	{
		m_pkValueTimerFlag = true;
		this->SetTimedo(PVP_TIMER_KILL_VALUE, 60*60*1000 - m_onlineTime, 1);
		m_onlineTime = 0;
		m_lastSubPkValueTime = g_GetGlobalServerTime()->Tick();
	}
}

void PvpPart::BeforeChangeLogic()
{
	if (m_pkValueTimerFlag)
	{
		m_onlineTime = g_GetGlobalServerTime()->Tick() - m_lastSubPkValueTime;
	}
}

bool PvpPart::Init(Creature *pMaster, uint32_t partType, CharacterDBInfo* pCharacterDB)
{
	Part::Init(pMaster, partType);
	if (m_pMaster->CreatureKind() == CREATURE_PLAYER)
	{
		g_GetEvent()->Subscribe(dynamic_cast<IEventExecuteSink*>(this), EVENT_CREATURE_DEAD, m_pMaster->GetCid(), CREATURE_PLAYER, NULL);
		g_GetEvent()->Subscribe(dynamic_cast<IEventExecuteSink*>(this), EVENT_UNDER_ATTACK, m_pMaster->GetCid(), 0, NULL);
		g_GetEvent()->Subscribe(dynamic_cast<IEventExecuteSink*>(this), EVENT_GUILD_CHANGE, m_pMaster->GetCid(), m_pMaster->CreatureKind(), NULL);
	}
	if (pCharacterDB && pCharacterDB->basedata().has_pvpdata())
	{
		const ::ProtoBuf::CharacterDBPvpData& pvpData = pCharacterDB->basedata().pvpdata();
		m_pkMode = pvpData.pk_mode();
		m_pkKillingValue = pvpData.pk_killing_value();
		m_onlineTime = pvpData.online_time();

		for(int i = 0; i < pvpData.red_player_size(); i++)
		{
			const ::ProtoBuf::RedPlayerInfo& info = pvpData.red_player(i);
			m_redStatus.emplace(info.cid(), info.time());
		}

		CountKillValueTimer();
	}

	//从文档中读
	//配置表存储用的是 unordered_map ,是无序的，这里取的可能不是按照 C级 B级 A级 S级 SSS级的顺序
	/*const PkmodePkWantedCfgMap * pWantedeMap=g_GetPkmodePkWantedCfgTable()->GetPkmodePkWantedCfgMap();
	if (pWantedeMap)
	{
		PkmodePkWantedCfgMap::const_iterator iter = pWantedeMap->begin();
		for (;iter != pWantedeMap->end();++iter)
		{
			m_vPKReadLineLimit.push_back(iter->second.strikeValue);
		}
	}*/

	g_GetPkModeCfgMgr()->GetPkLvLimit(m_vPKReadLineLimit);
	if ((int)m_vPKReadLineLimit.size()<g_const_PK_Level)
	{
		LogErrFmtPrint("PvpPart::Init pk level error....m_vPKReadLineLimit.size()< g_const_PK_Level ");
		return false;
	}
	
	//OnTimerHandleUpdat
	this->SetTimedo(PVP_TIMER_UPDATE, 1000);
	return true;
}

bool PvpPart::UnInit()
{
	g_GetEvent()->UnSubscribeAll(dynamic_cast<IEventExecuteSink*>(this));
	this->KillAllTimerdo();
	return true;
}

bool PvpPart::SaveDB(CharacterDBInfo& characterDB)
{
	::ProtoBuf::CharacterDBPvpData* pvpData = characterDB.mutable_basedata()->mutable_pvpdata();
	if (pvpData)
	{
		pvpData->set_pk_mode(m_pkMode);
		pvpData->set_pk_killing_value(m_pkKillingValue);
		pvpData->set_online_time(m_onlineTime);
		for(auto it = m_redStatus.begin(); it != m_redStatus.end(); it++)
		{
			::ProtoBuf::RedPlayerInfo* pInfo = pvpData->add_red_player();
			pInfo->set_cid(it->first);
			pInfo->set_time(it->second);
		}
	}
	return true;
}

bool PvpPart::SynOnLogin(PlayerClientInfo& playerInfo)
{
	playerInfo.set_pk_mode(m_pkMode);
	playerInfo.set_pk_killing_value(m_pkKillingValue);

	for(auto it = m_redStatus.begin(); it != m_redStatus.end(); it++)
	{
		::ProtoBuf::RedPlayerInfo* pInfo = playerInfo.add_red_player();
		pInfo->set_cid(it->first);
		pInfo->set_time(it->second);
	}
	return true;
}

bool PvpPart::OnMsgHandle(uint32_t cmd, const char* data, uint32_t len)
{
	switch (cmd)
	{
	case CLIENT_TO_SERVER_PVP_SET_MODE:
		MsgHandleSwitchPkMode(data, len);
		break;
	default:
		break;
	}
	return true;
}

void PvpPart::SendPvpKillingValue()
{
	PvpKillingValueBroadCast info;
	info.set_pk_killing_value(m_pkKillingValue);
	info.set_charid(m_pMaster->GetCid());
	m_pMaster->BroadCastData(SERVER_TO_CLIENT_PVP_KILLING_VALUE, &info, true);
}

void PvpPart::MsgHandleSwitchPkMode(const char* data, uint32_t len)
{
	PvpSetModeRequest request;

	if (!request.ParseFromArray(data, len))
	{
		MMOLOG_FMT_ERROR("[logic] ActorMove parse failed...");
		return;
	}

	if (m_pkMode != request.pk_mode())
	{
		m_pkMode = request.pk_mode();
	}

	PvpSetModeRespone respone;
	respone.set_retcode(0);
	respone.set_pk_mode(m_pkMode);
	respone.set_cid(m_pMaster->GetCid());
	m_pMaster->BroadCastData(SERVER_TO_CLIENT_RET_SET_MODE, &respone, true);
}

void PvpPart::OnExecute(uint16_t nEventID, uint64_t nSrcID, uint8_t bySrcType, void *pContext, int32_t nLen)
{
	switch (nEventID)
	{
	case EVENT_UNDER_ATTACK:
	{
		skillAttackEvent* attackEvent = (skillAttackEvent*)(pContext);
		CountBeAttack(attackEvent->attacker);
	}
	break;
	case EVENT_CREATURE_DEAD:
	{
		DieEvent *dieEvent = (DieEvent*)(pContext);

		//清理掉对应自己的红名玩家
		if (m_redStatus.find(dieEvent->nCid) != m_redStatus.end())
		{
			SubRedPlayer(dieEvent->nCid);
			m_redStatus.erase(dieEvent->nCid);
		}

	}
	break;
	case EVENT_GUILD_CHANGE:
	{
		if (m_pMaster->GetAttr(C_UNION_ID) == 0)
		{
			m_pkMode = PK_MODE_CAMP;
			PvpSetModeRespone respone;
			respone.set_retcode(0);
			respone.set_pk_mode(m_pkMode);
			respone.set_cid(m_pMaster->GetCid());
			m_pMaster->BroadCastData(SERVER_TO_CLIENT_RET_SET_MODE, &respone, true);
		}
		else
		{
			PvpSetModeRespone respone;
			respone.set_retcode(0);
			respone.set_pk_mode(m_pkMode);
			respone.set_cid(m_pMaster->GetCid());
			m_pMaster->BroadCastData(SERVER_TO_CLIENT_RET_SET_MODE, &respone, true);
		}
	}
	break;
	default:
		break;
	}
}

void PvpPart::CountBeAttack(CharIDType attackCid)
{
	Scene* pScene = m_pMaster->GetScene();
	if (pScene && m_pMaster->CreatureKind() == CREATURE_PLAYER)
	{
		Player* beAttackPlayer = dynamic_cast<Player*>(m_pMaster);
		if (beAttackPlayer)
		{
			Creature* attackCreature = pScene->GetCreature(attackCid);
			if (attackCreature)
			{
				if (attackCreature->CreatureKind() == CREATURE_PLAYER)
				{
					Player* attackPlayer = dynamic_cast<Player*>(attackCreature);
					if (attackPlayer)
					{
						PvpPart* attackPart = dynamic_cast<PvpPart*>(attackPlayer->GetPart(PART_PVP));
						if (beAttackPlayer->GetPkKillingValue() > 0 && beAttackPlayer->IsSameCamp(attackPlayer))
						{
							return;
						}
						else if (attackPart->IsRedPlayer(beAttackPlayer) == false)
						{
							PvpPart* beAttackPart = dynamic_cast<PvpPart*>(beAttackPlayer->GetPart(PART_PVP));
							beAttackPart->AddRedPlayer(attackPlayer);
						}
					}
				}
			}
		}
	}
}

const PkmodePkWantedCfgInfo* PvpPart::GetPkKillingValueConfig()
{
	/*const PkmodePkWantedCfgMap *pCfgMap = g_GetPkmodePkWantedCfgTable()->GetPkmodePkWantedCfgMap();
	for (PkmodePkWantedCfgMap::const_iterator it = pCfgMap->begin(); it != pCfgMap->end(); it++)
	{
		const PkmodePkWantedCfgInfo& info = it->second;
		if (m_pkKillingValue >= (uint32_t)info.minPKNum && m_pkKillingValue <= (uint32_t)info.maxPKNum)
		{
			return &info;
		}
	}
	return nullptr;*/
	return g_GetPkModeCfgMgr()->GetPkWantedCfgInfo(m_pkKillingValue);
}

void  PvpPart::CountPkKillingValue(CharIDType killerCid, CharIDType beKillerCid)
{
	Scene* pScene = m_pMaster->GetScene();
	if (pScene == nullptr)
	{
		return;
	}

	uint32_t mapId = pScene->GetMapId();
	const MapMapCfgInfo *pMapInfo = g_GetMapMapCfgTable()->GetMapMapCfgInfo(mapId);
	if (pMapInfo == nullptr)
	{
		return;
	}

	/* 新的表去掉了为 0的那条记录，所以这里需要先判断当前杀戮值为0的情况
	const PkmodePkWantedCfgInfo* cfgInfo = GetPkKillingValueConfig();
	if (cfgInfo == nullptr)
	{
		return;
	}*/

	Player* killPlayer = dynamic_cast<Player*>(pScene->GetCreature(killerCid));
	if (killPlayer == nullptr)
	{
		return;
	}

	Player* masterPlayer = dynamic_cast<Player*>(pScene->GetCreature(beKillerCid));
	if (masterPlayer == nullptr)
	{
		return;
	}

	if (killPlayer == masterPlayer)
	{
		return;
	}

	if (masterPlayer->InWorldBossStatus() || killPlayer->InWorldBossStatus())		//处于陨落诅咒状态下的玩家 击杀和被击杀相关角色不会增加杀戮值
		return;

	if (masterPlayer->RemitSonPKPunish() || killPlayer->RemitSonPKPunish())	//
	{
		return;
	}

	if (pMapInfo->mapPk == MAP_PK_RULE_CAN_PK)
	{
		//击杀同阵营非通缉状态下的玩家
		if (killPlayer->IsSameCamp(masterPlayer) || masterPlayer->IsNewPlayer())
		{
			if (masterPlayer->GetPkKillingValue() <= 0)
			{
				if (killPlayer->GetPkKillingValue() > 0)
				{
					killPlayer->AddPkKillingValue(1);
					killPlayer->SendPvpKillingValue();
				}
				else if (killPlayer->IsRedPlayer(masterPlayer) == false)
				{
					killPlayer->AddPkKillingValue(1);
					killPlayer->SendPvpKillingValue();
				}
			}
		}
	}

	//地图允许玩家死亡掉落
	if (pMapInfo->deadPunish == 1)
	{
		//PK掉落统一改到 玩家死亡掉落那边处理
		//g_GetDropMgr()->BeKilledDrop(masterPlayer, killPlayer);
	}
}

void PvpPart::OnTimer(uint32_t nTimerId)
{
	if (nTimerId == PVP_TIMER_UPDATE)
	{
		OnTimerHandleUpdate();
	}
	else if (nTimerId == PVP_TIMER_KILL_VALUE)
	{
		m_onlineTime = 0;
		m_lastSubPkValueTime = 0;

		const ConstantConstantCfgInfo *cfgInfo = g_GetConstantConstantCfgTable()->GetConstantConstantCfgInfo(EArg::EArg_subPkValueTenMinutes);
		if (cfgInfo)
		{
			SubPkKillingValue(cfgInfo->constantdata);
			SendPvpKillingValue();
		}

		m_pkValueTimerFlag = false;
		CountKillValueTimer();
	}
}

void PvpPart::OnTimerHandleUpdate()
{
	if (m_pkMode == 0 && m_pMaster->GetAttr(C_LEVEL) >= 1)
	{
		m_pkMode = PK_MODE_CAMP;
		PvpSetModeRespone respone;
		respone.set_retcode(0);
		respone.set_pk_mode(m_pkMode);
		respone.set_cid(m_pMaster->GetCid());
		m_pMaster->BroadCastData(SERVER_TO_CLIENT_RET_SET_MODE, &respone, true);
	}

	for (std::map<uint64_t, uint64_t>::iterator it = m_redStatus.begin(); it != m_redStatus.end();)
	{
		if (it->second < g_GetGlobalServerTime()->Tick())
		{
			SubRedPlayer(it->first);

			it = m_redStatus.erase(it);
			continue;
		}
		it++;
	}
}

void PvpPart::AddPkKillingValue(uint32_t addon)
{
	if (m_pkKillingValue >= 250) return;

	m_pkKillingValue += addon;

	CountKillValueTimer();

	//PKValuePunish();


	AngerChangeEvent info;
	info.cid = m_pMaster->GetCid();
	info.isAdd = true;
	info.value = addon;
	info.curValue = m_pkKillingValue;
	g_GetEvent()->FireExecute(EVENT_ANGER_CHANGE, m_pMaster->GetCid(), m_pMaster->CreatureKind(), (AngerChangeEvent*)&info, sizeof(AngerChangeEvent));
}


void PvpPart::SubPkKillingValue(uint32_t addon)
{
	if (m_pkKillingValue < addon)
	{
		m_pkKillingValue = 0;
	}
	else
	{
		m_pkKillingValue -= addon;
	}

	//PKValuePunish();

	AngerChangeEvent info;
	info.cid = m_pMaster->GetCid();
	info.isAdd = false;
	info.value = addon;
	info.curValue = m_pkKillingValue;
	g_GetEvent()->FireExecute(EVENT_ANGER_CHANGE, m_pMaster->GetCid(), m_pMaster->CreatureKind(), (AngerChangeEvent*)&info, sizeof(AngerChangeEvent));
}

uint32_t PvpPart::GetPkKillingValue() const
{
	return m_pkKillingValue;
}

uint32_t PvpPart::GetPkMode() const
{
	return m_pkMode;
}

void  PvpPart::SetPkMode(uint32_t pkMode)
{
	LogDebugFmtPrint("[logic] PvpPart::SetPkMode....cid:%llu ,old:%u , new:%u ", m_pMaster->GetCid(), m_pkMode, pkMode);
	if (m_pkMode != pkMode)
	{
		m_pkMode = pkMode;

		PvpSetModeRespone respone;
		respone.set_retcode(0);
		respone.set_pk_mode(m_pkMode);
		respone.set_cid(m_pMaster->GetCid());
		m_pMaster->BroadCastData(SERVER_TO_CLIENT_RET_SET_MODE, &respone, true);
	}
	
}

void PvpPart::ClearAllRedPlayer()
{
	for (std::map<uint64_t, uint64_t>::iterator it = m_redStatus.begin(); it != m_redStatus.end(); it++)
	{
		SubRedPlayer(it->first);
	}
	m_redStatus.clear();
}

void PvpPart::SubRedPlayer(CharIDType playerCid)
{
	PvpRedPlayer msg;
	msg.set_is_add(false);
	msg.set_player_cid(playerCid);

	m_pMaster->SendDataToClient(SERVER_TO_CLIENT_UPDATE_RED_PLAYER, &msg);
	g_GetEvent()->UnSubscribe(dynamic_cast<IEventExecuteSink*>(this), EVENT_CREATURE_DEAD, playerCid, CREATURE_PLAYER);
}


void PvpPart::AddRedPlayer(Player* player)
{
	if (player && player != m_pMaster)
	{
		const ConstantConstantCfgInfo *cfgInfo = g_GetConstantConstantCfgTable()->GetConstantConstantCfgInfo(EArg::EArg_attackRedTime);
		if (cfgInfo)
		{
			if (m_redStatus.find(player->GetCid()) == m_redStatus.end())
			{
				PvpRedPlayer msg;
				msg.set_is_add(true);
				msg.set_player_cid(player->GetCid());

				m_pMaster->SendDataToClient(SERVER_TO_CLIENT_UPDATE_RED_PLAYER, &msg);
				g_GetEvent()->Subscribe(dynamic_cast<IEventExecuteSink*>(this), EVENT_CREATURE_DEAD, player->GetCid(), player->CreatureKind(), NULL);
			}
			m_redStatus[player->GetCid()] = g_GetGlobalServerTime()->Tick() + cfgInfo->constantdata* 1000;
		}
	}
}

bool PvpPart::IsRedPlayer(Player* player)
{
	if (player)
	{
		if (m_redStatus.find(player->GetCid()) != m_redStatus.end())
		{
			return true;
		}
	}
	return false;
}

bool PvpPart::IsWanted() const //是否被通缉
{
	return m_pkKillingValue >= 3;
}



//获取杀戮惩罚的坐标和地图
bool PvpPart::GetPKValuePunishInfo(uint32_t &mapid,uint32_t & nSceneId, Point3<float> & nPos)
{
	return g_GetReliveMgr()->GetBanishReliveInfo(m_pMaster->GetMapId(), m_pMaster->GetSceneId(), m_pMaster->GetPos(), m_pMaster->GetAttr(C_CAMP_ID), m_pkKillingValue, mapid, nSceneId, nPos);
	/*//找到流放之地地图
	const ConstantConstantCfgInfo *pJailMapID = g_GetConstantConstantCfgTable()->GetConstantConstantCfgInfo(EArg_ClearPoint_Jail);
	if (nullptr == pJailMapID)
	{
		LogErrFmtPrint("[logic] Player::C2AttrClearPoint.....nullptr == pJailMapID, id:%d ", EArg_ClearPoint_Jail);
		return false;
	}

	uint32_t sceneid = pJailMapID->constantdata;
	if (m_pkKillingValue < m_vPKReadLineLimit[1] || m_pMaster->GetSceneId() == sceneid)
	{
		//小于A级的，不用在这惩罚,或者已在这个地图中，则不用再用这个判断了
		return false;
	}

	MovePart * pMovePart = dynamic_cast<MovePart*>(m_pMaster->GetPart(PART_MOVE));
	if (!pMovePart)
	{
		LogDebugFmtPrint("PvpPart::PKValuePunish pMovePart=NULL");
		return false;
	}

	//直接找默认的地图复活
	Point3<float> pos = g_GetMapLocationCfg()->GetNearRelivePos(sceneid, m_pMaster->GetPos(), m_pMaster->GetAttr(C_CAMP_ID));
	if (pos.length() <= 0)
	{
		LogDebugFmtPrint("find not relive pos PvpPart::PKValuePunish");
		return false;
	}


	if (m_pkKillingValue >= m_vPKReadLineLimit[1]) //此等级，只要在指定静态地图和公会地图死了，就直接传监狱
	{
		if (m_pMaster->IsDead())
		{
			nSceneId = sceneid;
			nPos = pos;
			return true;
		}
	}

	return false;*/
}


//杀戮值惩罚
bool  PvpPart::PKValuePunish()
{

	uint32_t sceneid = 0;
	uint32_t mapid = 0;
	Point3<float> pos(0.0, 0.0, 0.0);
	if (GetPKValuePunishInfo(mapid,sceneid, pos))
	{
		MovePart * pMovePart = dynamic_cast<MovePart*>(m_pMaster->GetPart(PART_MOVE));
		if (!pMovePart)
		{
			LogErrFmtPrint("PvpPart::PKValuePunish pMovePart=NULL cid:%lu ", m_pMaster->GetCid());
			return false;
		}
		STransParam transParam;
		transParam.transType = ETransType_PkPunish;
		transParam.srcMapId = m_pMaster->GetMapId();
		pMovePart->TransScene(sceneid, pos, sceneid, transParam);
		//直接复活，然后传送到监狱
		m_pMaster->OnRevive(m_pMaster->GetCid());
		return true;
	}

	return false;
}
